/*
 *
 *  This file is part of the SIRIUS library for analyzing MS and MS/MS data
 *
 *  Copyright (C) 2023 Bright Giant GmbH
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 3 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License along with SIRIUS.
 *  If not, see <https://www.gnu.org/licenses/lgpl-3.0.txt>
 */

package de.unijena.bioinf.lcms.detection;

import java.util.Arrays;

/**
 * Gaussian convolution for one dimensional arrays.
 */
public class GaussFilter {

    private final double[] kernel;

    public GaussFilter(double sigma) {
        this.kernel = computeKernel(sigma);
    }

    private double[] computeKernel(double sigma) {
        int radius = (int) Math.round(4.0 * sigma);
        double sigma2 = -0.5 / (sigma * sigma);
        double sum = 0;
        double[] k = new double[2 * radius + 1];
        for (int i = -radius; i < radius + 1; i++) {
            k[i + radius] = Math.exp(sigma2 * Math.pow(i, 2));
            sum += k[i + radius];
        }
        for (int i = 0; i < k.length; i++) {
            k[i] /= sum;
        }
        return k;
    }

    public double[] apply(double[] src) {
        int kw = (kernel.length  - 1) / 2;

        double[] dst = new double[src.length];
        for (int i = 0; i < src.length; i++) {
            dst[i] = 0;
            for (int di = -kw; di <= kw; di++) {
                if (i + di < 0)
                    dst[i] += kernel[di + kw] * src[0];
                else if (i + di >= src.length)
                    dst[i] += kernel[di + kw] * src[src.length - 1];
                else
                    dst[i] += kernel[di + kw] * src[i + di];
            }
        }

        return dst;
    }

    public static void main(String[] args) {
//        System.out.println(Arrays.toString(new GaussFilter(5).kernel));
        double[] trace = new double[]{
                810.0,1000.0,1011.0,794.0,932.0,711.0,1168.0,885.0,1085.0,837.0,900.0,805.0,1028.0,841.0,1286.0,739.0,907.0,664.0,191.0,30162.0,86778.0,14920.0,1762.0,777.0,416.0,365.0,253.0,155.0,1057.0,786.0,680.0,1531.0,2022.0,1206.0,1072.0,1107.0,1150.0,733.0,983.0,1116.0,878.0,1006.0,856.0,1171.0,538.0,1142.0,1055.0,1085.0,706.0,817.0,675.0,1103.0,926.0,914.0,958.0,987.0,899.0,1024.0,716.0,1059.0,1029.0,724.0,757.0,955.0,882.0,862.0,825.0,785.0,986.0,847.0,908.0,1049.0,1257.0,964.0,819.0,1010.0,1087.0,847.0,1322.0,1329.0,1091.0,735.0,819.0,708.0,685.0,2135.0,2000.0,667.0,346.0,558.0,569.0,513.0,754.0,789.0,897.0,754.0,1067.0,1202.0,891.0,671.0,911.0,581.0,867.0,971.0,742.0,615.0,808.0,712.0,875.0,958.0,542.0,928.0,666.0,676.0,820.0,694.0,507.0,788.0,962.0,751.0,600.0,713.0,872.0,630.0,767.0,907.0,1330.0,1099.0,1197.0,1473.0,582.0,913.0,701.0,1222.0,573.0,1706.0,1427.0,1229.0,1667.0,1392.0,1291.0,1034.0,2198.0,4127.0,1279.0,1757.0,1752.0,1499.0,2152.0,1968.0,956.0,1209.0,1673.0,1258.0,972.0,814.0,1427.0,1283.0,1289.0,2665.0,2108.0,1397.0,1648.0,4961.0,2157.0,1052.0,1117.0,490.0,1251.0,510.0,762.0,950.0,749.0,874.0,884.0,700.0,958.0,854.0,855.0,861.0,645.0,771.0,788.0,478.0,631.0,416.0,531.0,607.0,628.0,535.0,371.0,479.0,454.0,371.0,326.0,299.0,356.0,266.0,434.0,517.0,547.0,505.0,473.0,452.0,331.0,506.0,621.0,413.0,361.0,289.0,321.0,485.0,459.0,367.0,466.0,372.0,325.0,480.0,283.0,367.0,218.0,413.0,541.0,839.0,433.0,497.0,357.0,455.0,431.0,152.0,222.0,251.0,526.0,401.0,309.0,419.0,261.0,413.0,314.0,400.0,290.0,278.0,271.0,408.0,496.0,488.0,520.0,424.0,307.0,162.0,310.0,348.0,447.0,476.0,278.0,427.0,719.0,375.0,250.0,533.0,353.0,369.0,527.0,500.0,245.0,549.0,454.0,429.0,387.0,473.0,424.0,373.0,425.0,578.0,484.0,221.0,413.0,469.0,471.0,314.0,380.0,430.0,292.0,426.0,468.0,390.0,516.0,566.0,448.0,448.0,543.0,442.0,505.0,333.0,416.0,524.0,488.0,506.0,452.0,251.0,360.0,382.0,464.0,483.0,512.0,480.0,446.0,153.0,379.0,299.0,382.0,476.0,535.0,440.0,222.0,533.0,506.0,548.0,425.0,383.0,613.0,442.0,467.0,451.0,722.0,467.0,483.0,471.0,463.0,419.0,418.0,499.0,500.0,305.0,256.0,601.0,358.0,480.0,544.0,392.0,285.0,385.0,366.0,565.0,457.0,395.0,302.0,310.0,467.0,399.0,548.0,361.0,354.0,186.0,308.0,353.0,342.0,464.0,439.0,287.0,463.0,377.0,320.0,268.0,222.0,485.0,331.0,161.0,369.0,257.0,347.0,409.0,365.0,163.0,470.0,335.0,381.0,506.0,400.0,272.0,275.0,148.0,309.0,227.0,502.0,266.0,201.0,374.0,301.0,402.0,248.0,266.0,176.0,211.0,238.0,378.0,188.0,185.0,244.0,346.0,226.0,230.0,370.0,204.0,146.0,155.0,321.0,230.0,205.0,234.0,170.0,223.0,151.0,238.0,413.0,270.0,179.0,136.0,115.0,196.0,212.0,163.0,1128.0,1204.0,1571.0,2069.0,1637.0,1402.0,1664.0,2012.0,2347.0,2366.0,2354.0,2534.0,3044.0,2840.0,3093.0,3199.0,3465.0,3290.0,4301.0,4570.0,4683.0,4909.0,5144.0,5305.0,5500.0,5535.0,5504.0,6220.0,5224.0,6669.0,6063.0,6747.0,7359.0,7223.0,6508.0,8620.0,7789.0,7384.0,8048.0,7685.0,7501.0,8362.0,8611.0,8139.0,8227.0,7801.0,8495.0,9329.0,8925.0,9292.0,8481.0,8665.0,9003.0,8631.0,9392.0,9246.0,9823.0,8484.0,9273.0,7976.0,9175.0,9259.0,9427.0,9289.0,9345.0,8926.0,9084.0,9168.0,9811.0,9349.0,8558.0,9124.0,8085.0,8543.0,8360.0,8498.0,8918.0,8369.0,7914.0,8776.0,7290.0,8409.0,8140.0,7442.0,7284.0,8483.0,8286.0,8869.0,7949.0,6751.0,7442.0,7580.0,7490.0,7990.0,7224.0,7416.0,7819.0,7245.0,6504.0,6430.0,6563.0,7008.0,6384.0,6683.0,6441.0,6027.0,7005.0,6496.0,5433.0,6255.0,5715.0,5856.0,6028.0,5849.0,5105.0,6056.0,5518.0,5896.0,5579.0,5261.0,5689.0,5249.0,5322.0,5174.0,5796.0,6308.0,6376.0,6775.0,7963.0,10081.0,12235.0,20577.0,8123.0,4173.0,3417.0,2600.0,2204.0,1937.0,1461.0,1065.0,830.0,625.0,820.0,626.0,500.0,294.0,446.0,359.0,367.0,364.0,433.0,209.0,197.0,184.0,226.0,192.0,230.0,185.0,216.0,172.0,194.0,242.0,200.0,229.0,131.0,166.0,128.0
        };
        System.out.println(Arrays.toString(new GaussFilter(5).apply(trace)));
    }

}
